#include "stdafx.h"
#include "RayTraceMgr.h"
#include "GeometricTools.h"
#include "LogManager.h"

RayTraceMgr* RayTraceMgr::m_pInstance = 0;
RayTraceMgr::RayTraceMgr(void)
{
    m_vBuff1 = m_vBuff2 = m_vBuff3 = m_vBuff4 = NULL;
}
RayTraceMgr::~RayTraceMgr(void)
{
    ClearBuff();
}
void RayTraceMgr::Init(int nWidth, int nHeight, Vector3f vCameraPos, float fFov)
{

    m_fWidth  = nWidth;
    m_fHeight = nHeight;

    m_camera.Init(vCameraPos, fFov, nWidth, nHeight);

    m_scene.Init();

    m_tracer.Init(&m_scene);

    SetAntiAliasing(false);

    SetRayTraceDepth(1);  
    
    LogManager::GetInstance()->Init();
    LogManager::GetInstance()->Logln("RayTraceMgr init done.");

}
void RayTraceMgr::SetWidthAndHeight(int width, int height) 
{
	m_fWidth = width;
	m_fHeight = height;
}
void RayTraceMgr::Generate()
{
    LogManager::GetInstance()->BeginTime(0);

    ClearBuff();

    m_vBuff1 = new ColorValue[m_fWidth * m_fHeight];

    if (m_bAntiAliasing)
    {    
        m_vBuff2 = new ColorValue[m_fWidth * m_fHeight];
        m_vBuff3 = new ColorValue[m_fWidth * m_fHeight];
        m_vBuff4 = new ColorValue[m_fWidth * m_fHeight];
    }

    for (int i = 0; i < m_fWidth; ++i)
    {
        for (int j = 0; j < m_fHeight; ++j)
        {
            m_vBuff1[i * (int)m_fHeight + j] = ColorValue(0.5, 0.5, 0.5);
            if (m_bAntiAliasing)
            {    
                m_vBuff2[i * (int)m_fHeight + j] = ColorValue(0.5, 0.5, 0.5);
                m_vBuff3[i * (int)m_fHeight + j] = ColorValue(0.5, 0.5, 0.5);
                m_vBuff4[i * (int)m_fHeight + j] = ColorValue(0.5, 0.5, 0.5);
            }
        }
    }

    // test sphere
    float fSphereCenter[] = {-5, 5, -5, 1};
    float fSphereRadius = 5;
    float fResult[] = {0, 0, 0, 1};

    Vector3f vCameraPos = m_camera.GetPos();

    Material mat = Material::Air;
   
    for (int i = 0; i < m_fWidth; ++i)
    {
        float wx1 = (i - 0.25 - static_cast<float>(m_fWidth)/2.0) / m_fWidth * m_camera.GetScale();
        float wx2 = (i + 0.25 - static_cast<float>(m_fWidth)/2.0) / m_fWidth * m_camera.GetScale();
        for (int j = 0; j < m_fHeight; ++j)
        {
            float wy1 = (j - 0.25 - static_cast<float>(m_fHeight)/2.0) / m_fHeight * m_camera.GetScale();
            float wy2 = (j + 0.25 - static_cast<float>(m_fHeight)/2.0) / m_fHeight * m_camera.GetScale();


            // test trace
            //float fLinePos[] = {vCameraPos.x, vCameraPos.y, vCameraPos.z, 1};
            //float fLineDir[] = {wx - vCameraPos.x, wy - vCameraPos.y, -vCameraPos.z, 1};
            //float fLinePos[] = {-3.9692283, 3.4670970, -0.35374320 };
            //float fLineDir[] = {0.066564016, -0.30864125, 0.94884658 };

            //bool bIntersect = GeometricTools::LineIntersectSphere(
            //    fLineDir, fLinePos, fSphereCenter, fSphereRadius, fResult);
            //if (bIntersect)
            //{
            //    m_vBuff[i * (int)m_fHeight + j] = ColorValue::White;
            //}
            //else
            //{
            //    m_vBuff[i * (int)m_fHeight + j] = ColorValue::Black;
            //}

            // Test anti-aliasing
            Line line1(vCameraPos, Vector3f(wx1, wy1, 0));
            ColorValue color = m_tracer.Trace(line1, m_depth, mat);
            m_vBuff1[i * (int)m_fHeight + j] = color;

            if (m_bAntiAliasing)
            {   
                Line line2(vCameraPos, Vector3f(wx1, wy2, 0));
                ColorValue color2 = m_tracer.Trace(line2, m_depth, mat);
                m_vBuff2[i * (int)m_fHeight + j] = color2;

                Line line3(vCameraPos, Vector3f(wx2, wy1, 0));
                ColorValue color3 = m_tracer.Trace(line3, m_depth, mat);
                m_vBuff3[i * (int)m_fHeight + j] = color3;

                Line line4(vCameraPos, Vector3f(wx2, wy2, 0));
                ColorValue color4 = m_tracer.Trace(line4, m_depth, mat);
                m_vBuff4[i * (int)m_fHeight + j] = color4;
            }

        }// for
    }

    LogManager::GetInstance()->EndTime(0, "Generate time used:");
    LogManager::GetInstance()->Log("m_nTraced = ");
    LogManager::GetInstance()->Logln(m_tracer.m_nTraced);

    LogManager::GetInstance()->Log("m_nTracedReflect = ");
    LogManager::GetInstance()->Logln(m_tracer.m_nTracedReflect);

    LogManager::GetInstance()->Log("m_nTracedRefract = ");
    LogManager::GetInstance()->Logln(m_tracer.m_nTracedRefract);
}
void RayTraceMgr::Render()
{           
    glBegin(GL_POINTS);
    //glColor3f(1, 0, 0);
    //glVertex2f(100, 300);
    // left  : x = 0
    // bottom: y = 0
    ColorValue color;
    for (int i = 0; i < m_fWidth; ++i )
    {
        for (int j = 0; j < m_fHeight; ++j )
        {
            int index = i * m_fHeight + j; 
            if (m_bAntiAliasing)
            {   
				ColorValue tempColor = m_vBuff1[index] + m_vBuff2[index] + m_vBuff3[index] + m_vBuff4[index];
//                 float r =  m_vBuff1[index].R() + m_vBuff2[index].R() + m_vBuff3[index].R() + m_vBuff4[index].R()/**/;
//                 float g =  m_vBuff1[index].G() + m_vBuff2[index].G() + m_vBuff3[index].G() + m_vBuff4[index].G()/**/;
//                 float b =  m_vBuff1[index].B() + m_vBuff2[index].B() + m_vBuff3[index].B() + m_vBuff4[index].B()/**/;
                glColor3f(tempColor.R()*0.25, tempColor.G()*0.25, tempColor.B()*0.25);
//				glColor3f(r*0.25, g*0.25, b*0.25);
            }
            else
            {           
                glColor3f(m_vBuff1[index].R(), m_vBuff1[index].G(), m_vBuff1[index].B());
            }
            glVertex2f(i, j);
        }
    }
    glEnd();

    glutSwapBuffers();
}


void RayTraceMgr::SetLight(const GLfloat *pPosition, const GLfloat *pAmbient, const GLfloat *pDiffuse,
              const GLfloat *pSpecular, GLfloat fMass)
{
    //memcpy(m_fvLightPos, pPosition, sizeof(GLfloat)*4);
    //memcpy(m_fvAmbient, pAmbient, sizeof(GLfloat)*4);
    //memcpy(m_fvDiffuse, pDiffuse, sizeof(GLfloat)*4);
    //memcpy(m_fvSpecular, pSpecular, sizeof(GLfloat)*4);
    //m_fMass = fMass;
}

